﻿using SuperSocket.ClientEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace ACEPAPI
{
    /// <summary>
    /// ESC/POS客户端 - 使用SuperSocket.AsyncTcpSession
    /// </summary>
    public class EPClientAsyncTcpSession : EPClientBase
    {
        #region 定义与变量
        /// <summary>
        /// AsyncTcpSession对象
        /// </summary>
        private AsyncTcpSession TcpSession;

        /// <summary>
        /// 是否已经连接
        /// </summary>
        private bool IsConnected => TcpSession != null && TcpSession.IsConnected;

        /// <summary>
        /// 是否保持连接(连接超时后自动重连)
        /// </summary>
        public bool KeepConnect { get; set; }

        /// <summary>
        /// 是否手动关闭连接
        /// </summary>
        private bool _IsManualDisconnect = false;


        public delegate void ABSStatusEventHandler(object sender, ABSStatus e);
        public delegate void DataEventHandler(object sender, byte[] bytes, int offset, int length);
        public delegate void ErrorEventHandler(object sender, Exception e);

        public event ABSStatusEventHandler OnStateChanged;
        public event DataEventHandler OnDataReceived;
        public event ErrorEventHandler OnError;
        public event EventHandler OnConnected;
        public event EventHandler OnClosed;


        #endregion

        #region 构造与释放
        public EPClientAsyncTcpSession(string ipAdd,int ipPort)
        {
            //检测IP地址与端口
            IPAddress _IPAdd;
            if (!IPAddress.TryParse(ipAdd, out _IPAdd))
            {
                throw new ApplicationException("指定的打印机没有正确设置ip地址，无法打印");
            }
            IPAddress = _IPAdd;
            if (ipPort >= 0 && ipPort <= 65535)
            {
                IPPort = ipPort;
            }
            else
            {
                throw new ApplicationException("指定的打印机没有正确设置端口地址，无法打印");
            }
        }

        public EPClientAsyncTcpSession(string ipAdd,int ipPort,bool keepConnect)
        {
            //检测IP地址与端口
            IPAddress _IPAdd;
            if (!IPAddress.TryParse(ipAdd, out _IPAdd))
            {
                throw new ApplicationException("指定的打印机没有正确设置ip地址，无法打印");
            }
            IPAddress = _IPAdd;
            if (ipPort >= 0 && ipPort <= 65535)
            {
                IPPort = ipPort;
            }
            else
            {
                throw new ApplicationException("指定的打印机没有正确设置端口地址，无法打印");
            }
            KeepConnect = keepConnect;
        }

        ~ EPClientAsyncTcpSession()
        {
            Dispose();
        }

        public override void Dispose()
        {
            if (TcpSession != null)
            {
                TcpSession.Connected -= TcpSession_Connected;
                TcpSession.Closed -= TcpSession_Closed;
                TcpSession.Error -= TcpSession_Error;
                TcpSession.DataReceived -= TcpSession_DataReceived;
            }
                
            TcpSession?.Close();
            TcpSession = null;
        }
        #endregion

        /// <summary>
        /// 建立连接
        /// </summary>
        public void Connect()
        {
            if (IsConnected)
            {
                return;
            }
            _IsManualDisconnect = false;
            TcpSession = new AsyncTcpSession();
            TcpSession.Connected += TcpSession_Connected;
            TcpSession.Closed += TcpSession_Closed;
            TcpSession.Error += TcpSession_Error;
            TcpSession.DataReceived += TcpSession_DataReceived;
            TcpSession.Connect(new IPEndPoint(IPAddress, IPPort));
        }

        /// <summary>
        /// 重新连接
        /// </summary>
        public void Reconnect()
        {
            if (IsConnected)
            {
                _IsManualDisconnect = true;
                TcpSession.Close();
            }
            TcpSession.Connect(new IPEndPoint(IPAddress, IPPort));
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            _IsManualDisconnect = true;
            TcpSession?.Close();
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sendBytes">要发送数据</param>
        /// <returns>是否发送</returns>
        public void Send(byte[] sendBytes)
        {
            try
            {
                if (IsConnected)
                {
                    TcpSession.SendingQueueSize = sendBytes.Length;
                    TcpSession.Send(sendBytes, 0, sendBytes.Length);
                }
            }
            catch(Exception x)
            {
                OnError?.Invoke(null, x);
            }
        }
        /// <summary>
        /// 获取数据事件
        /// </summary>
        private void TcpSession_DataReceived(object sender, DataEventArgs e)
        {
            OnDataReceived?.Invoke(sender, e.Data, e.Offset, e.Length);
            if (e.Length <= 0) { return; }
            byte[] buffer;
            

            /*
             * 处理长度为4字节,以0x0F结束的返回数据
             * 自动状态返回 GS a n / 1D 61 n
             * n值:n = 0:禁用自动状态返回
             * 0:0 / 1:抽屉连接器状态已禁用 / 启用
             * 1:0 / 1:在线离线状态已禁用 / 启用
             * 2:0 / 1:错误状态已禁用 / 启用
             * 3:0 / 1:卷纸传感器状态已禁用 / 启用
             * 4:0 / 1:保留
             * 5:0 / 1:保留
             * 6:0 / 1:面板开关状态已禁用 / 启用
             * 7:0 / 1:保留
            */
            if (e.Length==4)
            {
                buffer = new byte[e.Length];
                Array.Copy(e.Data, buffer, e.Length);
                if(buffer[3].Equals(Convert.ToByte(0x0F)))
                {
                    OnStateChanged?.Invoke(sender, new ABSStatus(buffer));
                }
                
            }
        }

        /// <summary>
        /// 出现错误事件
        /// </summary>
        private void TcpSession_Error(object sender, ErrorEventArgs e)
        {
            OnError?.Invoke(sender, e.Exception);
        }

        /// <summary>
        /// 连接已关闭事件
        /// </summary>
        private void TcpSession_Closed(object sender, EventArgs e)
        {
            OnClosed?.Invoke(sender, e);
            if (KeepConnect && !_IsManualDisconnect)
            {
                Reconnect();
            }
        }
        /// <summary>
        /// 连接已建立事件
        /// </summary>
        private void TcpSession_Connected(object sender, EventArgs e)
        {
            OnConnected?.Invoke(sender, e);
        }
    }
}
